package org.edu.eece262.taskshare;

import java.lang.reflect.Type;
import java.util.LinkedList;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;

public class GroupDBAdapter {
	
	// Let's be a Singleton
	private static GroupDBAdapter instance = null;

	// Member Variables
	private static String DB_NAME = "Group.db";
	private static final String DB_TABLE = "LocalGroups";

	private static final int DB_VERSION = 20;

	public static final String DB_KEY_ID = "_id";

	// Public Key (Column) Names for convenience
	public static final String KEY_NAME = "Name";
	public static final String KEY_OWNER = "Owner";
	public static final String KEY_MEMBERS_NAMES = "Members";
	public static final String KEY_MEMBERS_ROLLS = "Rolls";
	public static final String KEY_MEMBERS_STATUS = "Status";

	// Public Column numbers for convenience
	public static final int NAME_COLUMN = 1;
	public static final int OWNER_COLUMN = 2;
	public static final int MEMBERS_NAMES_COLUMN = 3;
	public static final int MEMBERS_ROLLS_COLUMN = 4;
	public static final int MEMBERS_STATUS_COLUMN = 5;

	private static final String DB_CREATE = "create table " + DB_TABLE + " ("
			+ DB_KEY_ID + " integer primary key autoincrement, "
			+ KEY_NAME + " long, " + KEY_OWNER + " text, " + KEY_MEMBERS_NAMES + 
			" text, " + KEY_MEMBERS_ROLLS + 
			" text, " + KEY_MEMBERS_STATUS + " text);";

	private SQLiteDatabase db;

	private final Context context;
	private DBHelper dbHelper;
	private static Gson gson;
	
	public static final String PREFS_NAME = "TASKSHARELOGIN";

	public static GroupDBAdapter getGroupDBA(Context _context) {
		SharedPreferences settings = _context.getSharedPreferences(PREFS_NAME, 0);
		if(instance == null || !(DB_NAME.equals(settings.getString("user", "") + "Group.db"))) {
			DB_NAME = settings.getString("user", "") + DB_NAME;
			instance = new GroupDBAdapter(_context);
			gson = new Gson();
			instance.open();
			return instance;
		} else {
			return instance;
		}
	}
	
	private GroupDBAdapter(Context _context) {
		context = _context;
		dbHelper = new DBHelper(context, DB_NAME, null, DB_VERSION);
	}
	
	@SuppressWarnings("unchecked")
	public static LinkedList<Messages.GroupMember> groupMembersFromCursor(Cursor c) {
		Messages.Group group = new Messages.Group();
		Type stringlist = new TypeToken<LinkedList<String>>(){}.getType();
		group.setMemberName((LinkedList<String>) gson.fromJson(c.getString(MEMBERS_NAMES_COLUMN), stringlist));
		group.setMemberRoll(fromStringList(c.getString(MEMBERS_ROLLS_COLUMN)));
		group.setMemberStatus(fromStringList(c.getString(MEMBERS_STATUS_COLUMN)));
		return group.getMembers();
	}
	
	private static LinkedList<Integer> fromStringList(String string) {
		LinkedList<Integer> ints = new LinkedList<Integer>();
		String[] strings = string.split(",");
		for(int i = 0; i < strings.length; i++) {
			ints.add(Integer.parseInt(strings[i]));
		}
		return ints;
	}
	
	private String fromIntList(LinkedList<Integer> ints) {
		String string = "";
		for (int i = 0; i < ints.size(); i++) {
			string = string + ints.get(i) + ",";
		}
		return string;
	}

	public GroupDBAdapter open() throws SQLException {
		db = dbHelper.getWritableDatabase();
		return this;
	}

	public void close() {
		db.close();
	}

	public long insertEntry(String name, String owner, LinkedList<Messages.GroupMember> members, Context context) {
		ContentValues contentValues = new ContentValues();
		contentValues.put(KEY_NAME, name);
		contentValues.put(KEY_OWNER, owner);
		Messages.Group tempGroup = new Messages.Group().setMembers(members);
		contentValues.put(KEY_MEMBERS_NAMES, gson.toJson(tempGroup.getMemberName()));
		contentValues.put(KEY_MEMBERS_ROLLS, fromIntList(tempGroup.getMemberRoll()));
		contentValues.put(KEY_MEMBERS_STATUS, fromIntList(tempGroup.getMemberStatus()));
		
		int key = -1;
		
		if(HTTPHelp.getActivityHTTPHelp().createGroup(name, members, context)) {
			key =  (int) db.insert(DB_TABLE, null, contentValues);
		}
		
		return key;
	}
	
	public int addMembers(String name, String owner, LinkedList<Messages.GroupMember> members, Context context) {
		ContentValues contentValues = new ContentValues();
		contentValues.put(KEY_NAME, name);
		contentValues.put(KEY_OWNER, owner);
		Messages.Group tempGroup = new Messages.Group().setMembers(members);
		contentValues.put(KEY_MEMBERS_NAMES, gson.toJson(tempGroup.getMemberName()));
		contentValues.put(KEY_MEMBERS_ROLLS, fromIntList(tempGroup.getMemberRoll()));
		contentValues.put(KEY_MEMBERS_STATUS, fromIntList(tempGroup.getMemberStatus()));
		
		if(HTTPHelp.getActivityHTTPHelp().updateGroup(name, owner, members, context)) {
			return 0;
		}
		
		return -1;
	}
	
	public int updateOrCreateFromGlobal(Messages.Group group) {
		int key = -1;
		Cursor c = db.query(DB_TABLE, null, KEY_NAME + "= '" + group.getGroupName() + "'", null, null, null, null);
		if(c.getCount() > 0) {
			String where = KEY_NAME + "= '" + group.getGroupName() + "'";
			ContentValues contentValues = new ContentValues();
			contentValues.put(KEY_NAME, group.getGroupName());
			contentValues.put(KEY_OWNER, group.getOwner());
			contentValues.put(KEY_MEMBERS_NAMES, gson.toJson(group.getMemberName()));
			contentValues.put(KEY_MEMBERS_ROLLS, fromIntList(group.getMemberRoll()));
			contentValues.put(KEY_MEMBERS_STATUS, fromIntList(group.getMemberStatus()));
			
			key = db.update(DB_TABLE, contentValues, where, null);
		} else {
			ContentValues contentValues = new ContentValues();
			contentValues.put(KEY_NAME, group.getGroupName());
			contentValues.put(KEY_OWNER, group.getOwner());
			contentValues.put(KEY_MEMBERS_NAMES, gson.toJson(group.getMemberName()));
			contentValues.put(KEY_MEMBERS_ROLLS, fromIntList(group.getMemberRoll()));
			contentValues.put(KEY_MEMBERS_STATUS, fromIntList(group.getMemberStatus()));
			
			key = (int) db.insert(DB_TABLE, null, contentValues);
		}
		return key;
	}
	
	public int Modify(Messages.Group group, Context context) {
		if (HTTPHelp.getActivityHTTPHelp().updateGroup(group.getGroupName(), group.getOwner(), group.getMembers(), context)) {
			String where = KEY_NAME + "= '" + group.getGroupName() + "'";
			ContentValues contentValues = new ContentValues();
			contentValues.put(KEY_NAME, group.getGroupName());
			contentValues.put(KEY_OWNER, group.getOwner());
			contentValues.put(KEY_MEMBERS_NAMES, gson.toJson(group.getMemberName()));
			contentValues.put(KEY_MEMBERS_ROLLS, fromIntList(group.getMemberRoll()));
			contentValues.put(KEY_MEMBERS_STATUS, fromIntList(group.getMemberStatus()));
			
			return db.update(DB_TABLE, contentValues, where, null);
		}
		return -1;
	}

	public boolean deleteGroup(String name, Context context) {
		Cursor c = getGroupWithName(name);
		c.moveToFirst();
		if(c.getCount() > 0) {
			if(HTTPHelp.getActivityHTTPHelp().deleteGroup(name, context))
				return db.delete(DB_TABLE, KEY_NAME + "='" + name + "'", null) > 0;
			else
				return false;
		} else {
			return false;
		}
	}
	
	public Cursor getGroupWithName(String name) {
		return db.query(DB_TABLE, null, KEY_NAME + "='" + name + "'", null, null, null, null);
	}
	
	public Cursor getActiveGroups() {
		return db.query(DB_TABLE, null, null, null, null, null, null);
	}
	
	public int getUserRoll(String group_name, String user) {
		LinkedList<String> members = getGroupMemberNames(group_name);
		LinkedList<Integer> rolls = getGroupMemberRoll(group_name);
		for (int i = 0; i < members.size(); ++i) {
			if (members.get(i).equalsIgnoreCase(user)) {
				return rolls.get(i);
			}
		}
		return -1;
	}
	
	public LinkedList<String> getGroupMemberNames(String name) {
		Cursor c = getGroupWithName(name);
		c.moveToFirst();
		if(c.getCount() > 0) {
			Type stringlist = new TypeToken<LinkedList<String>>(){}.getType();
			return gson.fromJson(c.getString(MEMBERS_NAMES_COLUMN), stringlist);
		} else {
			return null;
		}
	}
	
	public LinkedList<Integer> getGroupMemberStatus(String name) {
		Cursor c = getGroupWithName(name);
		c.moveToFirst();
		if(c.getCount() > 0) {
			return fromStringList(c.getString(MEMBERS_STATUS_COLUMN));
		} else {
			return null;
		}
	}
	
	public LinkedList<Integer> getGroupMemberRoll(String name) {
		Cursor c = getGroupWithName(name);
		c.moveToFirst();
		if(c.getCount() > 0) {
			return fromStringList(c.getString(MEMBERS_ROLLS_COLUMN));
		} else {
			return null;
		}
	}

	public Cursor getAllEntries() {
		return db.query(DB_TABLE, null, null, null, null, null, null);
	}

	private static class DBHelper extends SQLiteOpenHelper {
		public DBHelper(Context context, String name, CursorFactory factory,
				int version) {
			super(context, name, factory, version);
		}

		// Called when no database exists in
		// disk and the helper class needs
		// to create a new one.
		@Override
		public void onCreate(SQLiteDatabase _db) {
			_db.execSQL(DB_CREATE);
		}

		@Override
		public void onUpgrade(SQLiteDatabase _db, int _oldVersion,
				int _newVersion) {
			// Log the version upgrade.
			Log.w("TaskDBAdapter", "Upgrading from version " + _oldVersion
					+ " to " + _newVersion
					+ ", which will destroy all old data");

			_db.execSQL("DROP TABLE IF EXISTS " + DB_TABLE);

			onCreate(_db);
		}
	}
}
